#pragma once


/* Base class for all binders */
template <typename Ret, typename Args>
class FunctorInterface {
public:
    virtual Ret operator()(Args) const = 0;
    virtual ~FunctorInterface() {}
};


/* Binding to function pointer */
template <typename Ret, typename Args>
class _freeBinder : public FunctorInterface<Ret,Args>
{
public:
    virtual Ret operator()(Args args) const 
    {
        return m_func(args);
    }
    typedef Ret (*SlotFunction)(Args);
    _freeBinder(SlotFunction f) : m_func(f) {}

protected:
  SlotFunction m_func;
};

/* Binding to copy of another functor */
template <class Functor, typename Ret, typename Args>
class _functorBinder : public FunctorInterface<Ret,Args>
{
public:
    virtual Ret operator()(Args args) const 
    {
        return m_func(args);
    }
    _functorBinder(const Functor& f) : m_func(f) {}
protected:
  Functor m_func;
};

/* Bound member function binding */
template <class T, typename Ret, typename Args>
class _memberBinder : public FunctorInterface<Ret,Args>
{
public:
    typedef Ret (T::*F)(Args);
    virtual Ret operator()(Args args) const
    {
        return (m_pT->*m_func)(args);
    }
    _memberBinder(F f, T* t) : m_func(f), m_pT(t) {}
protected:
  F  m_func;
  T* m_pT;
};


template <typename Ret, typename Args>
class FunctorTemplate
{
public:
    Ret operator()(Args args) const
    {
        return (*m_functorInterface)(args);  // call the bound function
    }
    
    typedef Ret (*SlotFunction)(Args);
    
    FunctorTemplate(SlotFunction f)
    {
        m_functorInterface = new _freeBinder<Ret,Args>(f);
    }
    
    template <class T>
    FunctorTemplate(Ret (T::*f)(Args), T* target)
    {
        m_functorInterface = new _memberBinder<T,Ret,Args>(f, target);
    }
    
    template <typename Functor> 
    FunctorTemplate(const Functor& f)
    {
        m_functorInterface = new _functorBinder<Functor,Ret,Args>(f);
    }
    
    FunctorTemplate(FunctorInterface<Ret,Args>* si) : m_functorInterface(fi) {}
    FunctorTemplate(const FunctorTemplate<Ret,Args>& copy) : m_functorInterface(copy.m_functorInterface) {}

    void release() const
    {
        delete m_functorInterface;
    }

    bool IsEquivalentTo(FunctorTemplate<Ret,Args>& rhs) const
    {
        if(m_functorInterface == rhs.m_functorInterface)
        {
            return true;
        }

        return false;
    }

protected:
  FunctorInterface<Ret,Args>* m_functorInterface;
};


